local M = {}

local SymbolKind = {
    "File",
    "Module",
    "Namespace",
    "Package",
    "Class",
    "Method",
    "Property",
    "Field",
    "Constructor",
    "Enum",
    "Interface",
    "Function",
    "Variable",
    "Constant",
    "String",
    "Number",
    "Boolean",
    "Array",
    "Object",
    "key",
    "Null",
    "EnumMember",
    "Struct",
    "Event",
    "Operator",
    "TypeParameter",
}

-- [1] model
local Model = {
    index = 1,
    dataset = {},
    listeners = {}
}
function Model:new()
    local o = Model
    setmetatable(o, self)
    return o
end

function Model:watch(listener)
    table.insert(self.listeners, listener)
end

function Model:update()
    local symbol_params = { textDocument = vim.lsp.util.make_text_document_params() }
    local resp, err = vim.lsp.buf_request_sync(0, 'textDocument/documentSymbol', symbol_params, 10000)
    self.dataset = resp

    -- local json = require('json')
    -- local f = io.open('/Users/ary/.config/nvim/plugins/lsp-outline.nvim/zzzz.txt', 'w')
    -- f:write(json.encode(result))
    -- f:flush()
    -- f:close()
    -- print('done')
    if err==nil then
        for _,listener in pairs(self.listeners) do
            listener:update(self.dataset)
        end
    end

end

-- [2] viewer
local Viewer = {}
function Viewer:new()
    local v = Viewer
    setmetatable(v, self)
    return v
end

function Viewer:update(dataset)
    -- TODO
    local buf = vim.api.nvim_create_buf(false, true)
    vim.api.nvim_command('vsp')
    vim.api.nvim_command('wincmd l')
    local win_id = vim.api.nvim_get_current_win()
    vim.api.nvim_win_set_buf(win_id, buf)
    local lines = {}
    for _,scope in pairs(dataset) do
        local result = scope.result
        for _, item in pairs(result) do
            -- print(item.name, SymbolKind[item.kind])
            table.insert(lines, string.format('%s  %s', item.name, SymbolKind[item.kind]))
            if item.children then
                for _, child in pairs(item.children) do
                    --print('  '..child.name, SymbolKind[child.kind])
                    table.insert(lines, string.format('  %s  %s', child.name, SymbolKind[child.kind]))
                end
            end
        end
    end
    -- vim.api.nvim_win_set_config(win_id, {width=20, relative='win', row=1, col=1,height=100})
    vim.api.nvim_win_set_width(win_id, 40)
    vim.api.nvim_buf_set_lines(buf, 0, #lines, nil, lines)
end

-- [3] controller
local Controller = {
    model = Model:new(),
    viewer = Viewer:new(),
}
function Controller:new()
    local c = Controller
    setmetatable(c, self)
    self.model:watch(self.viewer)
    return c
end

function Controller:update()
    self.model:update()
end


-- [0] user interface
function M.setup(opts)
    vim.api.nvim_set_keymap('n', '<F10>', '<cmd>lua require("lsp-outline").test()<cr>', {})
end

local controller = Controller:new()
function M.test()
    controller:update()
end


return M
